package com.sec.android.app.myfiles.fragment.settings;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.InputType;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Checkable;
import android.widget.ListView;
import android.widget.TextView;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.activity.SettingsActivity;
import com.sec.android.app.myfiles.dialog.EditTextDialogFragment;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.log.SamsungAnalyticsLog;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.OptimizeStorageType;
import com.sec.android.app.myfiles.util.FileUtils;
import com.sec.android.app.myfiles.util.PreferenceUtils;
import com.sec.android.app.myfiles.util.UiUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class OptimizeStorageRangeSettings extends AbsSettingsFragment
        implements AdapterView.OnItemClickListener, EditTextDialogFragment.EditTextCallback {

    private static final String OPTIMIZE_STORAGE_TYPE = "optimize_storage_type";
    private static final String OPTIMIZE_STORAGE_RANGE_SETTINGS = "optimize_storage_range_settings";

    private static final int REQ_CODE_CREATE_CUSTOM_VALUE = 1000;
    private static final int REQ_CODE_EDIT_CUSTOM_VALUE = 1001;
    private static final int CUSTOM_POS = 3;

    private static final String MAXIMUM_SIZE_OF_LARGE_FILES = "1000000"; // 1000000 MB = 1000 GB = 1 TB
    private static final String MAXIMUM_TIME_OF_UNUSED_FILES = "1000"; // 1000 MONTH
    private static final String MINIMUM_VALUE = "1";

    private enum ErrorCode {
        NONE,
        CUSTOM_VALUE_ALREADY_EXIST,
    }

    private Values mPreferenceValues;
    private OptimizeStorageType mOptimizeStorageType = OptimizeStorageType.None;
    private ListView mListView;
    private TextView mTextView;
    private ItemAdapter mAdapter;
    private EditTextDialogFragment mEditDialog;
    private ErrorCode mLastError = ErrorCode.NONE;
    private Integer mCustomValueInEditing;
    private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;
    private static SamsungAnalyticsLog.ScreenPath sScreenPath;

    public static OptimizeStorageRangeSettings getInstance(OptimizeStorageType type) {
        OptimizeStorageRangeSettings fragment = new OptimizeStorageRangeSettings();
        sScreenPath = (type == OptimizeStorageType.LargeFiles) ? SamsungAnalyticsLog.ScreenPath.SETTINGS_GET_MORE_LARGE : SamsungAnalyticsLog.ScreenPath.SETTINGS_GET_MORE_UNUSED;

        Bundle args = new Bundle();
        args.putString(OPTIMIZE_STORAGE_TYPE, type.toString());
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            String type = args.getString(OPTIMIZE_STORAGE_TYPE);
            if (!TextUtils.isEmpty(type)) {
                mOptimizeStorageType = OptimizeStorageType.valueOf(type);
                mPreferenceValues = createPreferenceValues(mOptimizeStorageType);
            }
        }
        DisplayMetrics metrics = new DisplayMetrics();
        ((WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
        mDensityDpi = metrics.densityDpi;
    }

    private Values createPreferenceValues(OptimizeStorageType optimizeStorageType) {
        Values ret;
        switch (optimizeStorageType) {
            case LargeFiles:
                ret = new LargeFilesValues(getActivity());
                break;

            case UnusedFiles:
                ret = new OldFilesValues(getActivity());
                break;

            default:
                throw new IllegalArgumentException("Can't create preference values : Unsupported type.");
        }
        return ret;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.optimize_storage_range_settings_layout, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        mTextView = (TextView) view.findViewById(R.id.description);
        int id = AppFeatures.isTablet() ? R.string.gms_setting_description_tablet : R.string.gms_setting_description_phone;
        mTextView.setText(id);
        mListView = (ListView) view.findViewById(R.id.list);
        mListView.setOnItemClickListener(this);
        mAdapter = createAdapter();
        mListView.setAdapter(mAdapter);
        SettingsActivity activity = (SettingsActivity) getActivity();
        if (activity != null) {
            switch (mOptimizeStorageType) {
                case LargeFiles:
                    activity.setActionBar(R.string.header_find_files_larger_than);
                    break;
                case UnusedFiles:
                    activity.setActionBar(R.string.header_find_files_unused_for);
                    break;
            }
            activity.setScreenPath(sScreenPath);
        }

        UiUtils.setListViewHeightBasedOnChildren(mListView);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {

        if (newConfig.densityDpi != mDensityDpi) {
            mDensityDpi = newConfig.densityDpi;
            if (mEditDialog != null && mEditDialog.isAdded()) {
                mEditDialog.dismissAllowingStateLoss();
            }
        }
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private ItemAdapter createAdapter() {
        List<Integer> datas = mPreferenceValues.getDefaultValues();
        ItemAdapter ret = new ItemAdapter(getActivity(), this, datas);
        ret.setSelectedItemValue(mPreferenceValues.getSavedValue());
        List<Integer> customDatas = mPreferenceValues.getSavedCustomValues();
        if (customDatas != null) {
            Collections.sort(customDatas);
            ret.addCustomValues(customDatas);
        }
        return ret;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        int itemType = mAdapter.getItemViewType(position);

        if (itemType == ItemAdapter.ITEM_TYPE_CREATE_CUSTOM) {
            if (UiUtils.isValidClick(view.getId())) {
                showCustomValueInputDialog(REQ_CODE_CREATE_CUSTOM_VALUE, ListView.INVALID_POSITION);
                SamsungAnalyticsLog.sendLog(sScreenPath, SamsungAnalyticsLog.Event.CUSTOM, null);
            }
        } else if (itemType == ItemAdapter.ITEM_TYPE_CUSTOM) {
            if (UiUtils.isValidClick(view.getId())) {
                showCustomValueInputDialog(REQ_CODE_EDIT_CUSTOM_VALUE, position);
                SamsungAnalyticsLog.sendLog(sScreenPath, SamsungAnalyticsLog.Event.CUSTOM, null);
            }
        } else {
            Integer value = (Integer) mAdapter.getItem(position);
            Integer savedValue = mPreferenceValues.getSavedValue();
            if (!savedValue.equals(value)) {
                clearCheckedItem();
                if (view instanceof Checkable) {
                    ((Checkable) view).setChecked(true);
                    mAdapter.setSelectedItemValue((Integer) mAdapter.getItem(position));
                }
                if (value != null) {
                    SamsungAnalyticsLog.sendLog(sScreenPath, SamsungAnalyticsLog.Event.SELECT_ITEM, value.toString(), null);
                    mPreferenceValues.saveValue(value);
                }
            }
        }
    }

    private void setInputRangeInCustomValue(EditTextDialogFragment.Builder builder) {
        if (mOptimizeStorageType == OptimizeStorageType.LargeFiles) {
            builder.setInputRange(MINIMUM_VALUE, MAXIMUM_SIZE_OF_LARGE_FILES);
        } else {
            builder.setInputRange(MINIMUM_VALUE, MAXIMUM_TIME_OF_UNUSED_FILES);
        }
    }

    private void setInputUnitInCustomValue(EditTextDialogFragment.Builder builder) {
        Resources res = null;
        Context context = getContext();
        if (context != null) {
            res = getContext().getResources();
        }
        if (res != null) {
            if (mOptimizeStorageType == OptimizeStorageType.LargeFiles) {
                builder.setInputUnit(res.getString(R.string.megabyteShort));
            } else {
                builder.setInputUnit(res.getString(R.string.month));
            }
        }
    }

    private void showCustomValueInputDialog(int requestCode, int position) {
        int titleResId = mOptimizeStorageType == OptimizeStorageType.LargeFiles ?
                R.string.custom_size : R.string.custom_time;
        int okTextResId = R.string.menu_done;

        EditTextDialogFragment.Builder builder = new EditTextDialogFragment.Builder();
        switch (requestCode) {
            case REQ_CODE_EDIT_CUSTOM_VALUE:
                Integer targetValue = (Integer) mAdapter.getItem(position);
                builder.setDefaultText(String.valueOf(targetValue));
                mCustomValueInEditing = targetValue;
                break;
        }
        setInputRangeInCustomValue(builder);
        setInputUnitInCustomValue(builder);
        mEditDialog = builder.setEditTextCallback(this)
                .setInputType(InputType.TYPE_CLASS_NUMBER)
                .setOkText(okTextResId)
                .setTitle(titleResId)
                .build();
        mEditDialog.setTargetFragment(this, requestCode);
        mEditDialog.showAllowingStateLoss(getFragmentManager(), OPTIMIZE_STORAGE_RANGE_SETTINGS);

    }

    private void clearCheckedItem() {
        final int count = mListView.getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = mListView.getChildAt(i);
            if (child instanceof Checkable) {
                ((Checkable) child).setChecked(false);
            }
        }
    }

    @Override
    public boolean checkNameExist(String inputString) {
        return false;
    }

    @Override
    public boolean checkText(String inputString, Activity activity) {
        Integer inputValue = getIntegerValue(inputString);
        boolean ret = false;
        if (inputValue != null) {
            ret = !checkCustomValueAlreadyExist(inputValue);
            if (!ret) {
                showErrorMessage(inputString);
            }
        }
        return ret;
    }

    private boolean checkCustomValueAlreadyExist(Integer inputValue) {
        boolean alreadyExist;
        List<Integer> values = mPreferenceValues.getDefaultValues();
        List<Integer> savedCustomValues = mPreferenceValues.getSavedCustomValues();
        if (savedCustomValues != null) {
            values.addAll(savedCustomValues);
        }
        alreadyExist = values.contains(inputValue);
        if (mEditDialog != null) {
            if (alreadyExist && mEditDialog.getTargetRequestCode() == REQ_CODE_EDIT_CUSTOM_VALUE &&
                    inputValue.equals(mCustomValueInEditing)) {
                alreadyExist = false;
            }
        }
        if (alreadyExist) {
            mLastError = ErrorCode.CUSTOM_VALUE_ALREADY_EXIST;
        }
        return alreadyExist;
    }

    @Override
    public void onOK(String inputString, Activity activity) {
        if (checkText(inputString, activity)) {
            int requestCode = mEditDialog.getTargetRequestCode();
            Integer newCustomValue = getIntegerValue(inputString);
            if (newCustomValue != null) {
                if (requestCode == REQ_CODE_CREATE_CUSTOM_VALUE) {
                    addCustomValue(newCustomValue);
                } else if (requestCode == REQ_CODE_EDIT_CUSTOM_VALUE) {
                    updateCustomValue(mCustomValueInEditing, newCustomValue);
                }
                mEditDialog.dismiss();
            } else {
                Log.e(this, "input value is invalid");
                newCustomValue = -1;
            }
            SamsungAnalyticsLog.sendLog(sScreenPath, SamsungAnalyticsLog.Event.OK, (long) newCustomValue, null, null);
        }
    }

    private void showErrorMessage(String inputString) {
        String msg = null;
        switch (mLastError) {
            case CUSTOM_VALUE_ALREADY_EXIST:
                if (isAdded()) {
                    msg = getString(R.string.ps_already_exist, inputString);
                }
                break;
        }
        if (!TextUtils.isEmpty(msg) && mEditDialog != null) {
            mEditDialog.setInputErrorEnabled(true);
            mEditDialog.setInputError(msg);
        }
    }

    private void addCustomValue(Integer customValue) {
        List<Integer> savedValues = mPreferenceValues.getSavedCustomValues();
        if (savedValues == null) {
            savedValues = new ArrayList<>();
        }
        savedValues.add(customValue);
        mPreferenceValues.saveCustomValues(savedValues);
        mPreferenceValues.saveValue(customValue);
        mAdapter = createAdapter();
        mAdapter.setSelectedItemValue(customValue);
        mListView.setAdapter(mAdapter);
        UiUtils.setListViewHeightBasedOnChildren(mListView);
    }

    private void updateCustomValue(Integer oldCustomValue, Integer newCustomValue) {
        List<Integer> savedValues = mPreferenceValues.getSavedCustomValues();
        if (savedValues == null) {
            savedValues = new ArrayList<>();
        }
        savedValues.remove(oldCustomValue);
        savedValues.add(newCustomValue);
        mPreferenceValues.saveCustomValues(savedValues);
        mPreferenceValues.saveValue(newCustomValue);
        mAdapter = createAdapter();
        mAdapter.setSelectedItemValue(newCustomValue);
        mListView.setAdapter(mAdapter);
    }

    @Override
    public void onCancel(Activity activity) {
        SamsungAnalyticsLog.sendLog(sScreenPath, SamsungAnalyticsLog.Event.CANCEL, null);
    }

    private Integer getIntegerValue(String value) {
        Integer ret = null;
        if (!TextUtils.isEmpty(value)) {
            String regexStr = "^[0-9]*$";
            value = value.trim();
            if (value.matches(regexStr)) {
                value = removeLeadingZero(value);
                final String MAX_INTEGER = String.valueOf(Integer.MAX_VALUE);
                int length = value.length();
                int maxIntegerLength = MAX_INTEGER.length();
                boolean isBiggerThanMaxInteger = (length > maxIntegerLength) ||
                        ((length == maxIntegerLength) && (value.compareTo(MAX_INTEGER) > 0));
                if (isBiggerThanMaxInteger) {
                    ret = Integer.MAX_VALUE;
                } else {
                    ret = Integer.valueOf(value);
                }
            }
        }
        return ret;
    }

    private String removeLeadingZero(String value) {
        String ret = null;
        int length = value.length();
        if (length >= 2) {
            for (int i = 0; i < length; i++) {
                if (value.charAt(i) != '0') {
                    ret = value.substring(i, length);
                    break;
                }
            }
        } else {
            ret = value;
        }
        return ret != null ? ret : "0";
    }

    private void updateSettingValue(String stateId, String inputValue, String maxValue) {
    }

    private static class ItemAdapter extends BaseAdapter {

        private static final int MAX_CUSTOM_VALUE_COUNT = 1;
        public static final int ITEM_TYPE_DEFAULT = 0;
        public static final int ITEM_TYPE_CUSTOM = 1;
        public static final int ITEM_TYPE_CREATE_CUSTOM = 2;

        private Context mContext;
        private OptimizeStorageType mOptimizeStorageType = OptimizeStorageType.None;
        private List<Integer> mDatas;
        private Integer mSelectedItemValue;
        private int mCustomValueCount;

        public ItemAdapter(Context context, OptimizeStorageRangeSettings parent, List<Integer> datas) {
            mContext = context;
            mOptimizeStorageType = parent.mOptimizeStorageType;
            mDatas = datas;
        }

        public void setSelectedItemValue(Integer value) {
            mSelectedItemValue = value;
        }

        public void addCustomValues(List<Integer> customValues) {
            if (customValues != null) {
                if (mDatas != null) {
                    mDatas.addAll(customValues);
                } else {
                    mDatas = customValues;
                }
                mCustomValueCount = customValues.size();
            }
        }

        @Override
        public int getCount() {
            int size = mDatas.size();
            return mCustomValueCount == MAX_CUSTOM_VALUE_COUNT ? size : size + 1;
        }

        @Override
        public Object getItem(int position) {
            if (mCustomValueCount != MAX_CUSTOM_VALUE_COUNT && position >= mDatas.size()) {
                return null;
            } else {
                return mDatas.get(position);
            }
        }

        @Override
        public long getItemId(int position) {
            long ret;
            if (mCustomValueCount != MAX_CUSTOM_VALUE_COUNT && position >= mDatas.size()) {
                ret = -1;
            } else {
                ret = mDatas.get(position);
            }
            return ret;
        }

        @Override
        public int getViewTypeCount() {
            return 3;
        }

        @Override
        public int getItemViewType(int position) {
            int size = mDatas.size();
            if (position < size - mCustomValueCount) {
                return ITEM_TYPE_DEFAULT;
            } else if (position < size) {
                return ITEM_TYPE_CUSTOM;
            } else {
                return ITEM_TYPE_CREATE_CUSTOM;
            }
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (mContext != null) {
                if (convertView == null) {
                    convertView = LayoutInflater.from(mContext).inflate(R.layout.optimize_storage_range_settings_item, parent, false);
                }
                if (convertView != null) {
                    switch (getItemViewType(position)) {
                        case ITEM_TYPE_DEFAULT:
                            displayDefaultItem(convertView, position);
                            break;
                        case ITEM_TYPE_CUSTOM:
                            displayCustomItem(convertView, position);
                            break;
                        case ITEM_TYPE_CREATE_CUSTOM:
                            displayCustomItem(convertView, -1);
                            break;
                    }

                    if (convertView instanceof Checkable) {
                        boolean needCheck = (mSelectedItemValue != null && position < mDatas.size() && mSelectedItemValue.equals(mDatas.get(position)));
                        ((Checkable) convertView).setChecked(needCheck);
                    }

                }
            }
            return convertView;
        }

        private void displayDefaultItem(View convertView, int position) {
            TextView text = (TextView) convertView.findViewById(R.id.text);
            if (text != null) {
                Resources res = mContext.getResources();
                switch (mOptimizeStorageType) {
                    case LargeFiles:
                        text.setText(String.format(Locale.getDefault(),
                                "%d %s", mDatas.get(position), res.getString(R.string.megabyteShort)));
                        break;
                    case UnusedFiles:
                        Integer month = mDatas.get(position);
                        text.setText(UiUtils.getQuantityString(res, R.plurals.opt_abb_pd_months, month, month));
                        break;
                }
            }
        }

        private void displayCustomItem(View convertView, int position) {
            TextView text = (TextView) convertView.findViewById(R.id.text);
            int customTypeString = R.string.custom_size;
            if (text != null) {
                if (mOptimizeStorageType == OptimizeStorageType.UnusedFiles) {
                    customTypeString = R.string.custom_time;
                }
                text.setText(customTypeString);
                if (UiUtils.isTalkBackEnabled(mContext)) {
                    View createCustom = convertView.findViewById(R.id.layout_container);
                    createCustom.setContentDescription(UiUtils.getHomeDescription(mContext, customTypeString, R.string.button));
                }
            }

            if (position != -1) {
                TextView custom = (TextView) convertView.findViewById(R.id.custom);
                if (custom != null) {
                    custom.setVisibility(View.VISIBLE);
                    Resources res = mContext.getResources();
                    switch (mOptimizeStorageType) {
                        case LargeFiles:
                            custom.setText(String.format(Locale.getDefault(),
                                    "%d %s", mDatas.get(position), res.getString(R.string.megabyteShort)));
                            break;
                        case UnusedFiles:
                            Integer month = mDatas.get(position);
                            custom.setText(UiUtils.getQuantityString(res, R.plurals.opt_abb_pd_months, month, month));
                            break;
                    }
                }
            }
        }
    }


    private interface Values {
        List<Integer> getDefaultValues();

        Integer getSavedValue();

        void saveValue(int value);

        List<Integer> getSavedCustomValues();

        void saveCustomValues(List<Integer> values);
    }

    private static class LargeFilesValues implements Values {

        private static final Integer[] DEFAULT_LARGE_FILES_SIZE = {
                25, 100, 500
        };

        private Context mContext;


        public LargeFilesValues(Context context) {
            mContext = context;
        }

        @Override
        public List<Integer> getDefaultValues() {
            ArrayList<Integer> ret = new ArrayList<>();
            for (Integer value : DEFAULT_LARGE_FILES_SIZE) {
                ret.add(value);
            }
            return ret;
        }

        @Override
        public Integer getSavedValue() {
            return (int) (PreferenceUtils.getLargeFilesSize(mContext) / FileUtils.MEGA_BYTES);
        }

        @Override
        public void saveValue(int value) {
            PreferenceUtils.setLargeFilesSize(mContext, value * FileUtils.MEGA_BYTES);
        }

        @Override
        public List<Integer> getSavedCustomValues() {
            return PreferenceUtils.getCustomLargeFilesSize(mContext);
        }

        @Override
        public void saveCustomValues(List<Integer> values) {
            PreferenceUtils.setCustomLargeFileSize(mContext, values);
        }
    }


    private static class OldFilesValues implements Values {

        private static final Integer[] DEFAULT_UNUSED_FILES_PERIOD = {
                6, 9, 12
        };

        private Context mContext;


        public OldFilesValues(Context context) {
            mContext = context;
        }

        @Override
        public List<Integer> getDefaultValues() {
            ArrayList<Integer> ret = new ArrayList<>();
            for (Integer value : DEFAULT_UNUSED_FILES_PERIOD) {
                ret.add(value);
            }
            return ret;
        }

        @Override
        public Integer getSavedValue() {
            return PreferenceUtils.getUnusedFilesPeriod(mContext);
        }

        @Override
        public void saveValue(int value) {
            PreferenceUtils.setUnusedFilesPeriod(mContext, value);
        }

        @Override
        public List<Integer> getSavedCustomValues() {
            return PreferenceUtils.getCustomUnusedFilesPeriod(mContext);
        }

        @Override
        public void saveCustomValues(List<Integer> values) {
            PreferenceUtils.setCustomUnusedFilePeriod(mContext, values);
        }
    }
}
